#include <vector>
#include <string>
#include <iostream>
#include <fstream>

#include "program.h"
#include "function.h"
#include "util.h"
#include "antlradapter.h"

using namespace std;


Program::Program(string ProjectPath)
{
DirectoryPath=ProjectPath;
C_LR=new AntlrAdapter();
}

Program::~Program()
{
delete C_LR;
}

void Program::Process()
{
int TempLineCount=-1;
//cout<<"File to open"<<DirectoryPath.c_str()<<endl;
ifstream SourceCodeFile;
SourceCodeFile.open(DirectoryPath.c_str());
string Line;
bool InFunction=false;//To keep track if I'm currently in a function or outside a function
///File is available and can read it
if(SourceCodeFile.is_open())
	{
	while(SourceCodeFile.good())
		{
			TempLineCount++;
			getline(SourceCodeFile,Line);
			///Deny all non-function declarations and variables and defs
			if((int(Line.find("#define"))==0)||(int(Line.find("#include"))==0)||((InFunction==false)&&(int(Line.find(';'))>=0)))
				;
			else if(InFunction==false&&(int(Line.find('('))>=0))///Found a function
			{
			int SpaceCount=0;
			while(!(int(Line.find('{'))>=0))//Find function opening
				{
				string temp;
				getline(SourceCodeFile,temp);
				TempLineCount++;
				Line+=temp;
				SpaceCount++;
				}
			///Create the function object and add it to the functions available
			Function newfunc(Line,TempLineCount+SpaceCount);
			Functions.push_back(newfunc);
			InFunction=true;
			}
			else if(InFunction==true)///In function=> add line to current function pointer
			{
			InFunction=Functions.back().AddLine(Line);//send the line to the top of stack vector and check if returns false, false should be returned only if function closed => set function_mode=false;
			//cout<<"Added "<<line<<endl;
			}
			else
			{
			;
			}
		}
	SourceCodeFile.close();
	}
else
	{
	cout<<"file couldnt be opeend"<<endl;
	}
}

string Program::GetFunctionNames()
{

//Returns the functions in the program in a numbered way
unsigned int Count=0;
string FunctionsNames="";
while(Count<Functions.size())
	{
	FunctionsNames+=ConvertIntToString(Count);
	FunctionsNames+=") ";
	FunctionsNames+=Functions.at(Count).GetNameParametrized();
	FunctionsNames+="\n";
	Count++;
	}

return FunctionsNames;
}

int Program::GetFunctionsCount()
{
	return Functions.size();
}

string Program::GetLinesOfFunctionAtPosition(int FunctionPosition)
{
	return Functions.at(FunctionPosition).GetLines();
}

string Program::GetFunctionLineAtPosition(int FunctionPosition,int LinePosition)
{
	return Functions.at(FunctionPosition).GetLineAtPosition(LinePosition);
}

int Program::GetFunctionLineScopeAtPosition(int FunctionPosition, int LinePosition)
{
return Functions.at(FunctionPosition).GetScopeOfLineAtPosition(LinePosition);
}

string Program::GetFunctionNameAtPosition(int FunctionPosition)
{
return Functions.at(FunctionPosition).GetNameParametrized();
}

int Program::GetFunctionFilePosition(int FunctionPosition)
{
return Functions.at(FunctionPosition).GetPositionInFile();
}

int Program::GetDBIdentificationKey()
{
return DBIdentificationKey;
}

int Program::FindLineNewPosition(int FunctionPosition, int LineScope, string LineDescription, string DescriptionType)
{
///Find the position of lines by description in the program
for(int temp=0;temp<Functions.at(FunctionPosition).GetLineCount();temp++)
	{
	if(DescriptionType.compare("def")==0)///def line description provided
		{
		if((C_LR->Def((Functions.at(FunctionPosition).GetLineAtPosition(temp))).compare(LineDescription)==0) && ((Functions.at(FunctionPosition).GetScopeOfLineAtPosition(temp))==LineScope))
			{
			return (Functions.at(FunctionPosition).GetPositionInFile()+temp);
			}
		}
	else if(DescriptionType.compare("use")==0)///use description provided
		{
		if((C_LR->Use((Functions.at(FunctionPosition).GetLineAtPosition(temp))).compare(LineDescription)==0) && ((Functions.at(FunctionPosition).GetScopeOfLineAtPosition(temp))==LineScope))
			{
			return (Functions.at(FunctionPosition).GetPositionInFile()+temp);
			}
		}
	}
return -1; ///=> line not found
}

string Program::GetDirectoryPath()
{
return DirectoryPath;
}
